Create Mass Property Description

Author

Yuta Nakajima

Published

March 15, 2024

Workflow ?@sec-introduction

flowchart LR
  A([Run Fuseki]) --> B([Query Data])
  B --> C((Tidy Data))
  C --> D([Tree: WP])
  C --> E([Tree: Configuration])
  C --> F([Table: Mass Property])
  D --> G([Decomposition Tree])
  E --> G
  G --> H([Roll up Calculations])
  F --> H
  H --> I([Report])
  

System Decomposition12

library(igraph)

searchDirectory <- function(iteration, pattern, parent_directory){
  for(i in 1:iteration){
      path <- list.files(parent_directory, recursive = TRUE, pattern = pattern, full.names = TRUE)
      if(length(path)){
        return(path)
      }
      parent_directory <- dirname(parent_directory)
  }
  print("file not found")
  return(path)
}

source(searchDirectory(4, "osr_common.R", (getwd())))
source(searchDirectory(4, "massRollup.R", (getwd())))

omlrepo
[1] "/Users/mlab/Workspaces/github/open-source-rover/"

Run Fuseki

Build and Start Fuseki server for oml model query

library(omlhashiR)
## oml_repository <- "../open-source-rover/"
# oml_repository <- omlrepo
# omlhashiR::oml_refresh()
# omlhashiR::oml_stop_Daemon(oml_repository)
# omlhashiR::oml_build(oml_repository)
# omlhashiR::oml_startFuseki(oml_repository)
# omlhashiR::oml_owlLoad(oml_repository)

Query

# Analysis: Finding Edges of the Containment Graph from Oml Model{#sec-introduction}

library(tansakusuR)

Attaching package: 'tansakusuR'
The following object is masked from 'package:dplyr':

    show_query
endpoint_url <- "http://localhost:3030/open-source-rover/sparql"

repo <- paste0(omlrepo, "src/vision/sparql/")

Tree: WP

Get wp authorizes wp

file <- "edge_workpackage.sparql"
filepath <- paste0(repo,file)
#show_query(filepath)
df_wp <- send_query_from_file(endpoint_url, filepath)
# datatable(df_wp, options = list(pageLength = -1))]
df_wp
# A tibble: 11 × 4
   parent                 child                              componentType iri  
   <chr>                  <chr>                              <chr>         <chr>
 1 wp-system              wp-CDHSubsystem                    http://imce.… http…
 2 wp-system              wp-ControlSubsystem                http://imce.… http…
 3 wp-system              wp-MechanicalSubsystem             http://imce.… http…
 4 wp-system              wp-MobilitySubsystem               http://imce.… http…
 5 wp-system              wp-NavigationSubsystem             http://imce.… http…
 6 wp-system              wp-PowerSubsystem                  http://imce.… http…
 7 wp-MechanicalSubsystem wp-body-assembly                   http://imce.… http…
 8 wp-MobilitySubsystem   wp-corner-wheel-assembly           http://imce.… http…
 9 wp-MobilitySubsystem   wp-drive-wheel-assembly            http://imce.… http…
10 wp-MechanicalSubsystem wp-mechanical-harness              http://imce.… http…
11 wp-MechanicalSubsystem wp-rocker-bogie-suspension-assemb… http://imce.… http…

Tree: WP

file <- "edge_suppliedComponents.sparql"
filepath <- paste0(repo,file)
#show_query(filepath)
df_c <- send_query_from_file(endpoint_url, filepath)
# datatable(df_c, options = list(pageLength = -1))
df_c
# A tibble: 11 × 4
   parent                              child                 componentType iri  
   <chr>                               <chr>                 <chr>         <chr>
 1 wp-body-assembly                    body-assembly         http://imce.… http…
 2 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 3 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 4 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 5 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 6 wp-drive-wheel-assembly             drive-wheel-assembly… http://imce.… http…
 7 wp-drive-wheel-assembly             drive-wheel-assembly… http://imce.… http…
 8 wp-mechanical-harness               mechanical-harness    http://imce.… http…
 9 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
10 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
11 wp-system                           OSR                   http://imce.… http…

Analysis: Create Containment Graph

root <- "OSR"


df <- rbind(df_wp, df_c)

# swap parent and child of root
index <- which(df$child==root)
c<-df$child[index]
p<-df$parent[index]
df$child[index]<-p
df$parent[index]<-c

g <- graph_from_data_frame(df[,c("parent","child")], 
                           directed = TRUE, 
                           vertices = NULL)


plot(g, layout=layout_as_tree)

Tree: Configuration

### <TBD> Analysis: Read Current Mass Property Data in Model

order <- dfs(g, V(g)[root], order.out = TRUE)$order

file <- "node_systemassemblymass.sparql"
filepath <- paste0(repo,file)
#show_query(filepath)
df_mass <- send_query_from_file(endpoint_url, filepath) %>%
  mutate(mass = replace_na(as.numeric(m),0)) %>% 
  arrange(factor(parent, levels = names(order)))

df_mass2 <- df_mass

ここまではOK。ただしサブシステムの情報を組み込んだMELのテンプレを新たに用意する必要がある。 マスロールアップは、サブシステムを含むgraphデータを探索することになるので、グラフデータを起点にした方が良いかもしれない。 例えば、あるコンフィグレーションの node_systemassemblymass.sparql を実行する。 これとワークパッケージを対応づける必要がある。

order <- dfs(g, V(g)[root], order.out = TRUE)$order

df_mel <- igraph::as_data_frame(g, what = "vertices") %>%
  arrange(factor(name, levels = names(order)))

df_mel2 <- left_join(df_mel, df_mass2, by = c("name"="parent"))

この処理の問題点は、owner情報が失われている点である。

  • edge_workpackage.sparql
  • edge_suppliedComponents.sparql
  • node_systemassemblymass.sparql

様々なコンフィグレーションに対応するためにも、 System -> Assemblyのコンフィグレーションを取り出す必要がある。 現状は、node_systemassemblymass.sparql の処理がそれに該当する。

df_wp
# A tibble: 11 × 4
   parent                 child                              componentType iri  
   <chr>                  <chr>                              <chr>         <chr>
 1 wp-system              wp-CDHSubsystem                    http://imce.… http…
 2 wp-system              wp-ControlSubsystem                http://imce.… http…
 3 wp-system              wp-MechanicalSubsystem             http://imce.… http…
 4 wp-system              wp-MobilitySubsystem               http://imce.… http…
 5 wp-system              wp-NavigationSubsystem             http://imce.… http…
 6 wp-system              wp-PowerSubsystem                  http://imce.… http…
 7 wp-MechanicalSubsystem wp-body-assembly                   http://imce.… http…
 8 wp-MobilitySubsystem   wp-corner-wheel-assembly           http://imce.… http…
 9 wp-MobilitySubsystem   wp-drive-wheel-assembly            http://imce.… http…
10 wp-MechanicalSubsystem wp-mechanical-harness              http://imce.… http…
11 wp-MechanicalSubsystem wp-rocker-bogie-suspension-assemb… http://imce.… http…
df_c
# A tibble: 11 × 4
   parent                              child                 componentType iri  
   <chr>                               <chr>                 <chr>         <chr>
 1 wp-body-assembly                    body-assembly         http://imce.… http…
 2 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 3 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 4 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 5 wp-corner-wheel-assembly            corner-wheel-assembl… http://imce.… http…
 6 wp-drive-wheel-assembly             drive-wheel-assembly… http://imce.… http…
 7 wp-drive-wheel-assembly             drive-wheel-assembly… http://imce.… http…
 8 wp-mechanical-harness               mechanical-harness    http://imce.… http…
 9 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
10 wp-rocker-bogie-suspension-assembly rocker-bogie-suspens… http://imce.… http…
11 wp-system                           OSR                   http://imce.… http…
df_mass
# A tibble: 11 × 8
   parent                             id    name   m     type  owner iri    mass
   <chr>                              <chr> <chr>  <chr> <chr> <chr> <chr> <dbl>
 1 OSR                                C.01  Rover… 1640… Syst… wp-s… http…  1640
 2 body-assembly                      A.01  Body … 30.0  Asse… wp-b… http…    30
 3 mechanical-harness                 A.10  Mecha… 50.0  Asse… wp-m… http…    50
 4 rocker-bogie-suspension-assembly-1 A.08  Rocke… 40.0  Asse… wp-r… http…    40
 5 rocker-bogie-suspension-assembly-2 A.09  Rocke… 40.0  Asse… wp-r… http…    40
 6 corner-wheel-assembly-1            A.04  Corne… 25.0  Asse… wp-c… http…    25
 7 corner-wheel-assembly-2            A.05  Corne… 25.0  Asse… wp-c… http…    25
 8 corner-wheel-assembly-3            A.06  Corne… 25.0  Asse… wp-c… http…    25
 9 corner-wheel-assembly-4            A.07  Corne… 25.0  Asse… wp-c… http…    25
10 drive-wheel-assembly-1             A.02  Drive… 15.0  Asse… wp-d… http…    15
11 drive-wheel-assembly-2             A.03  Drive… 15.0  Asse… wp-d… http…    15

Visualize Configuration

This might be generated by model query directly. Because we use system-subsystem-assembly configurations now, we produce this dataframe manually.

df_config<- df_mass %>%
  mutate(owner="OSR") %>%
  mutate(name=paste0(parent)) %>%
  mutate(type=paste0("contains")) %>%
  select("owner","name","type")

df_config$owner[df_config$name == "OSR"] <- NA

g2 <- graph_from_data_frame(df_config, 
                           directed = TRUE, 
                           vertices = NULL)
Warning in graph_from_data_frame(df_config, directed = TRUE, vertices = NULL):
In `d' `NA' elements were replaced with string "NA"
plot(g2, layout=layout_as_tree)

df_deg <- data.frame(
  name = names(degree(g2)),
  degree = degree(g2),
  distance = distances(g2)["NA",]
)

df_config <- df_config %>%
  left_join(df_deg, by=c("name"))

plotCollapsibleTreeFromDataframe(df_config, palette="BluYl", parent="owner", child="name",type="distance")

Visualize wp

df2<- df_wp %>%
  mutate(owner=paste0(parent)) %>%
  mutate(name=paste0(child)) %>%
  mutate(type=paste0("authorizes")) %>%
  select("owner","name","type") %>%
  add_row(owner=NA, name="wp-system", type="root")

g2 <- graph_from_data_frame(df2, 
                           directed = TRUE, 
                           vertices = NULL)
Warning in graph_from_data_frame(df2, directed = TRUE, vertices = NULL): In `d'
`NA' elements were replaced with string "NA"
plot(g2, layout=layout_as_tree)

df_deg <- data.frame(
  name = names(degree(g2)),
  degree = degree(g2),
  distance = distances(g2)["NA",]
)

df2 <- df2 %>%
  left_join(df_deg, by=c("name"))



plotCollapsibleTreeFromDataframe(df2, palette="BluYl", parent="owner", child="name",type="distance")

wp tree + “wp supplies components”

# I want to plot graph as dendrogram. graph doesnt have NA root for plotCollapsibleTreeFromDataframe
plotGraph2Dendrogram <- function(g){
  
  # find root nodes
  root_wp <- which(degree(g, mode = "in") == 0)
  root_wp <- names(root_wp)

  # Add NA
  df <- igraph::as_data_frame(g, what = "edges") %>%
    add_row(from=NA, to=root_wp)
  
  
  g2 <- graph_from_data_frame(df, 
                           directed = TRUE, 
                           vertices = NULL)

  df_deg <- data.frame(
    name = names(degree(g2)),
    degree = degree(g2),
    distance = distances(g2)["NA",]
  )
  
  df_g <- df %>%
    left_join(df_deg, by=c("to"="name")) 
  
  p<-plotCollapsibleTreeFromDataframe(df_g, palette="BluYl", parent="from", child="to",type="distance")
  
  
  return(p)
}
df_wp_2<- df_wp %>%
  mutate(owner=paste0(parent)) %>%
  mutate(name=paste0(child)) %>%
  mutate(type=paste0("authorizes")) %>%
  select("owner","name","type")

df_c_2<- df_c %>%
  mutate(owner=paste0(parent)) %>%
  mutate(name=paste0(child)) %>%
  mutate(type=paste0("supplies")) %>%
  select("owner","name","type")

df2<- rbind(df_wp_2, df_c_2)
df_g <- df2  
# df_g <- df2 %>% 
#   add_row(owner=NA, name="wp-system", type="root")

# 
# df2<- rbind(df_wp, df_c) %>%
#   mutate(owner=paste0(parent)) %>%
#   mutate(name=paste0(child)) %>%
#   mutate(type=paste0("Component")) %>%
#   select("owner","name","type") %>%
#   add_row(owner=NA, name="wp-system", type="root")

g2 <- graph_from_data_frame(df_g, 
                           directed = TRUE, 
                           vertices = NULL)


plot(g2, layout=layout_as_tree)

plotGraph2Dendrogram(g2)
Warning in graph_from_data_frame(df, directed = TRUE, vertices = NULL): In `d'
`NA' elements were replaced with string "NA"
# find root nodes
root_wp <- which(degree(g2, mode = "in") == 0)
root_wp <- names(root_wp)

root_nodes <- df_mass$parent[df_mass$owner == root_wp]

# Replace root_wp as root_nodes
df2[df2 == root_wp] <- root_nodes
df2$owner[df2$name == root_nodes] <- NA

  
g3 <- graph_from_data_frame(df2, 
                           directed = TRUE, 
                           vertices = NULL)
Warning in graph_from_data_frame(df2, directed = TRUE, vertices = NULL): In `d'
`NA' elements were replaced with string "NA"
plot(g3, layout=layout_as_tree)

df_deg <- data.frame(
  name = names(degree(g3)),
  degree = degree(g3),
  distance = distances(g3)["NA",]
)

df_g <- df2 %>%
  left_join(df_deg, by=c("name"="name")) 

plotCollapsibleTreeFromDataframe(df_g, palette="BluYl", parent="owner", child="name",type="distance")
plotGraph2Dendrogram(g3)
Warning in graph_from_data_frame(df, directed = TRUE, vertices = NULL): In `d'
`NA' elements were replaced with string "NA"

Currently below subsystems miss assemblies with mass data

order <- dfs(g3, V(g3)[root], order.out = TRUE)$order

df_mel <- igraph::as_data_frame(g3, what = "vertices") %>%
  arrange(factor(name, levels = names(order)))%>%
  filter(name !="NA")


df_mel2 <- left_join(df_mel, df_mass2, by = c("name"="parent"))
df_mel2$mass[df_mel2$name=="wp-CDHSubsystem"] <- 100.0
df_mel2$mass[df_mel2$name=="wp-ControlSubsystem"] <- 200.0
df_mel2$mass[df_mel2$name=="wp-NavigationSubsystem"] <- 300.0
df_mel2$mass[df_mel2$name=="wp-PowerSubsystem"] <- 400.0
namekey="name"
masskey="mass"

df_mass_update <- massRollUp(g3, root, df_mel2, namekey = "name",masskey = "mass")
df_table <- df_mass_update %>%
  select(name, mass) %>%
  left_join(select(df_g, name, owner, type, distance), by=c("name"="name"))

df_table$owner[1] <- df_table$name[1]
library(reactable)

Attaching package: 'reactable'
The following object is masked from 'package:networkD3':

    JS
reactable(df_table, groupBy = "owner")

Update Mass Properties using Json

This process includes user interface of the VS-Code Extension.

json editor

Read Mass Properties from data

#path = "./data_massproperty.json"
#path = "./quarto_docs/chapters/04_massrollup/data_massproperty.json"
# path <- searchDirectory(4, "data_massproperty.json", dirname(getwd()))

# df_json <- read_json(path = path,  simplifyVector = TRUE)

Analysis: Mass Rollup By Depth-First Traversal

# df_mass_update <- massRollUp(g, root, df_json)

Compare: Current OML Descriptions vs JSON

# df_mass_compare <- left_join(df_mass_update, df_mass, by = c("c1_localname","c1_id","c1_name","c1_type"), suffix = c("", "_before"))
# df_mass_compare

Generate OML Descriptions

Create Instance

# df_instance <- data.frame(
#   name = df_mass_update$c1_localname,
#   instancename = paste0(df_mass_update$c1_localname,".mass.magnitude"),
#   mass = df_mass_update$c1_mass,
#   type = str_replace_all(df_mass_update$c1_type, c("System"="subsystems", "Subsystem"="subsystems", "Assembly"="assembly"))
#   ) 

Generate OML Mass Descriptions

# outputdir <- paste0(omlrepo,"src/oml/opencaesar.io/open-source-rover/description/mass/")
# outputfile <- paste0(outputdir, "masses.oml")
# omldescriptions <- generateOmlMassDescriptions(df_instance)

Generate OML File

# cat(file=outputfile, omldescriptions)

Update Json

# write_json(df_mass_update, path = path, pretty=TRUE)
# df2<- df %>%
#   mutate(c2_mass = df$c1_mass[match(unlist(df$c2_localname), df$c1_localname)]) %>%
#   mutate(owner=paste0(c2_localname," (", c2_mass," kg)")) %>%
#   mutate(name=paste0(c1_localname," (", c1_mass," kg)")) %>%
#   select("owner","name","c1_type")
# 
# # Set NA node for CollapsibleTree
# df2$owner[df2$owner=="NA (NA kg)"] <- NA
# 
# 
# plotCollapsibleTreeFromDataframe(df2, palette="BluYl", parent="owner", child="name",type="c1_type")

Some visualization experiments

networkD3::simpleNetwork

# df2<- df %>% 
#   mutate(owner=parent) %>%
#   mutate(name=child) %>%
#   select("owner","name") %>%
#   arrange(desc(owner))   
# 
# 
# library(networkD3)
# 
# networkD3::simpleNetwork(df2)